<?php
/**
 * datetime: 2023/6/12 23:56
 **/

namespace App\Common\Util;

use Sc\Util\Tool;
use Sc\Util\Tool\Url;
use think\facade\Route;
use think\route\RuleItem;

class RouteUtil
{

    /**
     * 解析到指定的可访问方法的 url
     *
     * @param callable|array $target 只接受以数组形式的可调用参数， 例：[A::class, 'index']
     * @param array          $query
     *
     * @return Url
     * @throws \Exception
     * @date 2023/6/13
     */
    public function to(callable|array $target, array $query = []): Tool\Url
    {
        return Tool::url(TP::route()->getCurrentUrl()->getDomain())
            ->setPath($this->getRoute($target))
            ->setQuery($query);
    }

    /**
     * 解析到指定的可访问方法的 url, 允许未命中，未命中为空
     *
     * @param callable|array $target
     * @param array $query
     * @return string
     */
    public function toAllowMiss(callable|array $target, array $query = []): string
    {
        try {
            return $this->to($target, $query)->url();
        } catch (\Exception $e) {
            return '';
        }
    }

    /**
     * 获取当前url
     *
     * @return Url
     * @date 2023/6/13
     */
    public function getCurrentUrl(): Tool\Url
    {
        $url    = TP::request()->url(true);

        return Tool::url($url);
    }

    /**
     * 获取当前路由规则信息
     *
     * @param string|null $method
     *
     * @return RuleItem|null
     */
    public function getCurrentRule(string $method = null): mixed
    {
        $rules = TP::request()->rule()->getRouter()->getRule(TP::request()->pathinfo());

        if ($method === null) {
            $method = TP::request()->method();
        }

        $rules = array_filter($rules, fn(RuleItem $ruleItem) => $ruleItem->getMethod() === strtolower($method));

        return current($rules) ?: null;
    }

    /**
     * 静态资源地址
     * @param string $path
     *
     * @return string
     */
    public function asset(string $path): string
    {
        if (str_starts_with($path, 'http')) {
            return $path;
        }

        $path = strtr($path, ['\\' => '/']);

        return $this->getCurrentUrl()->getDomain() . (str_starts_with($path, '/') ? '' : '/') . $path;
    }

    /**
     * 获取指定路由详情
     *
     * @param string $route
     * @return mixed|null
     */
    public function getInfo(string $route): mixed
    {
        return TP::request()->rule()->getRouter()->getRuleName()->getRule($route);
    }

    /**
     * 获取路由列表
     *
     * @return array
     */
    public function getRouteList(): array
    {
        return Route::getRuleList();
    }

    /**
     * 获取路由Path
     *
     * @param array|callable $target
     *
     * @return string
     * @throws \Exception
     */
    public function getRoute(array|callable $target): string
    {
        $target = strtolower(implode('@', $target));


        $allRule = TP::request()->rule()->getRouter()->getRuleName()->getName();

        if (empty($allRule[$target])) {
            throw new \Exception(sprintf("目标地址 %s 不可访问", $target));
        }

        return $this->correctRule($allRule[$target][0]['rule']);
    }

    /**
     * 根据域名绑定情况，纠正路由规则
     *
     * @param string $rule
     * @return string
     */
    public function correctRule(string $rule): string
    {
        if (TP::request()->server('SCRIPT_NAME') === '/index.php') {
            $appName = array_search(app('http')->getName(), TP::config('app.app_map')) ?: app('http')->getName();
            $appName .= '/';
        }else{
            $appName = '';
        }

        return $appName . $rule;
    }
}